﻿using RentACarRESTApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;

namespace RentACarRESTApi.Services
{
    public class ReservationsRepository
    {
        private string CacheKey = "ReservationsRepository";
        private HttpContext context;

        public ReservationsRepository()
        {
            context = HttpContext.Current;

            if (context != null)
            {
                if (context.Cache[CacheKey] == null)
                {
                    var reservations = new Dictionary<int, Reservation>()
                    {
                        { 1, new Reservation(idCarReserved: 1, startDate: new DateTime(2013, 10, 10), endDate: new DateTime(2013, 11, 5))},
                        { 2, new Reservation(idCarReserved: 3, startDate: new DateTime(2013, 10, 14), endDate: new DateTime(2013, 10, 17))}
                    };

                    context.Cache[CacheKey] = reservations;
                }
            }
        }

        public IEnumerable<Reservation> GetAllReservations()
        {
            return ((Dictionary<int, Reservation>)context.Cache[CacheKey]).Values;
        }

        public bool SaveReservation(Reservation reservation)
        {
            if (((Dictionary<int, Reservation>)context.Cache[CacheKey]).Values.Any
                    (x => x.IdCarReserved == reservation.IdCarReserved &&
                    ((x.StartDate >= reservation.StartDate && x.StartDate <= reservation.EndDate) ||
                    (x.EndDate >= reservation.StartDate && x.EndDate <= reservation.EndDate))))
            {
                return false;
            }
            reservation.ID = ((Dictionary<int, Reservation>)context.Cache[CacheKey]).Count() + 1;
            ((Dictionary<int, Reservation>)context.Cache[CacheKey]).Add(reservation.ID, reservation);

            return true;
        }

        internal bool ContainsReservation(int id)
        {
            return ((Dictionary<int, Reservation>)context.Cache[CacheKey]).ContainsKey(id);
        }

        internal bool UpdateReservation(Reservation reservation)
        {
            if (((Dictionary<int, Reservation>)context.Cache[CacheKey]).ContainsKey(reservation.ID))
            {
                // Check if the reservation already exists for this
                if (((Dictionary<int, Reservation>)context.Cache[CacheKey]).Values.Any
                    (x => x.IdCarReserved == reservation.IdCarReserved &&
                    ((x.StartDate >= reservation.StartDate && x.StartDate <= reservation.EndDate) ||
                    (x.EndDate >= reservation.StartDate && x.EndDate <= reservation.EndDate))))
                {
                    return false;
                }

                if (reservation.IdCarReserved != ((Dictionary<int, Reservation>)context.Cache[CacheKey])[reservation.ID].IdCarReserved)
                {
                    ((Dictionary<int, Reservation>)context.Cache[CacheKey])[reservation.ID].IdCarReserved = reservation.IdCarReserved;
                }

                if (reservation.StartDate != ((Dictionary<int, Reservation>)context.Cache[CacheKey])[reservation.ID].StartDate)
                {
                    ((Dictionary<int, Reservation>)context.Cache[CacheKey])[reservation.ID].StartDate = ((Dictionary<int, Reservation>)context.Cache[CacheKey])[reservation.ID].StartDate;
                }

                if (reservation.EndDate != ((Dictionary<int, Reservation>)context.Cache[CacheKey])[reservation.ID].EndDate)
                {
                    ((Dictionary<int, Reservation>)context.Cache[CacheKey])[reservation.ID].EndDate = reservation.EndDate;
                }

                return true;
            }

            return false;
        }

        internal bool ContainsReservationCarBetweenDates(int carId, DateTime startDate, DateTime endDate)
        {
            bool found = ((Dictionary<int, Reservation>)context.Cache[CacheKey]).Values.
                Any(reserv => reserv.IdCarReserved == carId && !(startDate > reserv.EndDate || endDate < reserv.StartDate));

            return found;
        }

        internal bool DeleteReservation(int id)
        {
            if (((Dictionary<int, Reservation>)context.Cache[CacheKey]).ContainsKey(id))
            {
                return ((Dictionary<int, Reservation>)context.Cache[CacheKey]).Remove(id);
            }

            return false;
        }

        internal Reservation GetReservation(int id)
        {
            if (((Dictionary<int, Reservation>)context.Cache[CacheKey]).ContainsKey(id))
            {
                return ((Dictionary<int, Reservation>)context.Cache[CacheKey])[id];
            }
            else
            {            
                var resp = new HttpResponseMessage(HttpStatusCode.NotFound)
                {
                    Content = new StringContent(string.Format("No reservation with ID = {0}", id)),
                    ReasonPhrase = "Reservation ID Not Found"
                };

                throw new System.Web.Http.HttpResponseException(resp);
            }   
        }
    }
}